package simulationEnviroment;

import homeMadeExceptions.Bd_AddrException;

import java.util.Vector;

import metric.CentralObservableUnit;
import simulationEngine.SimulationEngine;
import ui.observ.PhysicalNetworkObservableUnit;
import datatypes.BluetoothDeviceAddress;
import datatypes.HostAction;
import datatypes.HostActionType;
import datatypes.NetworkAction;
import datatypes.RosterAction;
import datatypes.RosterActionType;
import datatypes.ScenarioActionDescription;

public class Processor {

	//Variables
	private SimulationEngine engine = null;
	private Vector<ScenarioActionDescription> simulationStack = null;
	private Vector<NetworkAction> actionStack = null;
	private Vector<NetworkAction> queuedActions = null;
	private Vector<RosterAction> sabotageStack = null;
	private Vector<HostAction> hostActions = null;
	
	
	//if this boolean is true, the enviroment is prepared for executing the simulation
	//if it is false, the enviroment is already prepared, and the simulationStack is
	// reduced
	private boolean initialisation = true;
	
	//Methods
	public Processor(SimulationEngine engine){
		this.engine = engine;
	}
	
	
	@SuppressWarnings("unchecked")
	public void prepareEnviromentForNextStep () {
		//first delete Steps from Last execution
		sabotageStack = null;
		actionStack = null;
		hostActions = null;
		queuedActions = null;
		queuedActions = (Vector<NetworkAction>) engine.getSimulationEnviroment().getQueue().getNextStepActions().clone();
		engine.getSimulationEnviroment().getQueue().resetActionsForNextStep();
		if (queuedActions != null){
			//if an precalculation with the stored Actions is needed, this should be done here
//			for (NetworkAction action: queuedActions){
//				if (action.getLogType() == LogicalNetworkActionType.INQUIRY_SCAN){
//					
//				}
//			}
			actionStack = (Vector<NetworkAction>) queuedActions.clone();
		}
		//get the Actions should be done in this simulation = now the next Step
		if (this.isInitialisationFinished() && this.getSimulationStack().size() > 0 && this.getSimulationStack().firstElement() != null){
			ScenarioActionDescription tmp = this.getSimulationStack().firstElement();
			this.getSimulationStack().remove(0);
			//which Layer is affected?
			if (tmp.getLayer().equals("Discovery")){
				//What Type Of Action is it?
				if (tmp.getType().equals("NewService")){
					String hostID = tmp.getObjects().firstElement();
					tmp.getObjects().remove(0);
					try {
						this.getHostActions().add(new HostAction(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID), HostActionType.PROPAGATE_NEW_SERVICE, tmp.getObjects()));
					} catch (Bd_AddrException e) {
						e.printStackTrace();
						//Sollte nicht auftreten, und ja ich weiss, das ist schlechtes SE
					}
				} else if (tmp.getType().equals("UpdateService")) {
					String hostID = tmp.getObjects().firstElement();
					tmp.getObjects().remove(0);
					try {
						this.getHostActions().add(new HostAction(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID), HostActionType.UPDATE_SERVICE, tmp.getObjects()));
					} catch (Bd_AddrException e) {
						e.printStackTrace();
						//Sollte nicht auftreten, und ja ich weiss, das ist schlechtes SE
					}
				} else if (tmp.getType().equals("DeleteService")){
					String hostID = tmp.getObjects().firstElement();
					tmp.getObjects().remove(0);
					try {
						this.getHostActions().add(new HostAction(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID), HostActionType.DELETE_SERVICE, tmp.getObjects()));
					} catch (Bd_AddrException e) {
						e.printStackTrace();
						//Sollte nicht auftreten, und ja ich weiss, das ist schlechtes SE
					}
				} else if (tmp.getType().equals("NodeGoesOffline")){
					String hostID = tmp.getObjects().firstElement();
					try {
						this.getHostActions().add(new HostAction(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID), HostActionType.DISABLE_DEVICE_DP_API));
					} catch (Bd_AddrException e) {
						e.printStackTrace();
						//Sollte nicht auftreten, und ja ich weiss, das ist schlechtes SE
					}				
				} else if (tmp.getType().equals("RequestService")){
					String hostID = tmp.getObjects().firstElement();
					tmp.getObjects().remove(0);
					try {
						this.getHostActions().add(new HostAction(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID), HostActionType.REQUEST_SERVICE, tmp.getObjects()));
					} catch (Bd_AddrException e) {
						e.printStackTrace();
						//Sollte nicht auftreten, und ja ich weiss, das ist schlechtes SE
					}
				} else if (tmp.getType().equals("ListServices")){
					String hostID = tmp.getObjects().firstElement();
					try {
						this.getHostActions().add(new HostAction(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID), HostActionType.LIST_SERVICES));
					} catch (Bd_AddrException e) {
						e.printStackTrace();
						//Sollte nicht auftreten, und ja ich weiss, das ist schlechtes SE
					}
				}
			}  else if (tmp.getLayer().equals("Topology")){
				//what type of action is it?
				if (tmp.getType().equals("NewNode")){
					String hostID = tmp.getObjects().firstElement();
					try {
						this.getSabotageStack().add(new RosterAction(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID), null, RosterActionType.NODE_IS_NOW_ACTIVATED));
						this.getHostActions().add(new HostAction(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID), HostActionType.ENABLE_DEVICE_DP_API));
					} catch (Bd_AddrException e) {
						e.printStackTrace();
						//Sollte nicht auftreten, und ja ich weiss, das ist schlechtes SE
					}
				} else if (tmp.getType().equals("KillNode")){
					String hostID = tmp.getObjects().firstElement();
					try {
						this.getSabotageStack().add(new RosterAction(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID), null, RosterActionType.NODE_IS_NOW_DEACTIVATED));
						this.engine.getHostList().deactivateHost(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID));
						PhysicalNetworkObservableUnit.getInstance(engine.getID()).nodeRemoved(Integer.parseInt(hostID));
					} catch (Bd_AddrException e) {
						e.printStackTrace();
						//Sollte nicht auftreten, und ja ich weiss, das ist schlechtes SE
					}
				} else if (tmp.getType().equals("QuitNode")){
					String hostID = tmp.getObjects().firstElement();
					try {
						this.getSabotageStack().add(new RosterAction(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID), null, RosterActionType.NODE_IS_NOW_DEACTIVATED));
						this.getHostActions().add(new HostAction(new BluetoothDeviceAddress(hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID + ":" + hostID), HostActionType.DISABLE_DEVICE_DP_API));
					} catch (Bd_AddrException e) {
						e.printStackTrace();
						//Sollte nicht auftreten, und ja ich weiss, das ist schlechtes SE
					}
				} else if (tmp.getType().equals("RosterActionDrop")){
					String edgeID = tmp.getObjects().firstElement();
					this.getSabotageStack().add(new RosterAction(null, edgeID, RosterActionType.DROP_EDGE));
				}
			}
		}
		//add Timestep-Notifier
		for (String bd_addy : engine.getHostList().getActiveHosts().keySet()){
			try {
				this.getHostActions().add(new HostAction(new BluetoothDeviceAddress(bd_addy), HostActionType.TIMESTEP_NOTIFIER));
			} catch (Bd_AddrException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		//write Layout parameter for scheduler
		engine.getSimulationEnviroment().getQueue().setActions(actionStack);
	
	}
	
	
	public Vector<RosterAction> getSabotageStack (){
		if (sabotageStack == null){
			sabotageStack = new Vector<RosterAction>();
		}
		return this.sabotageStack;
	}
	
	public Vector<NetworkAction> getActionStack () {
		if (actionStack == null){
			actionStack = new Vector<NetworkAction>();
		}
		return this.actionStack;
	}
	
	private Vector<ScenarioActionDescription> getSimulationStack (){
		if (this.simulationStack == null){
			this.simulationStack = engine.getScenarioParameter().getActions();
		}
		return this.simulationStack;
	}
	
	public void invokeMiniworldInitialisation (){
		engine.getMiniworld().initMiniworld();
	}
	
	public Vector<HostAction> getHostActions(){
		if (hostActions == null){
			hostActions = new Vector<HostAction>();
		}
		return hostActions;
	}

	
	private boolean isInitialisationFinished (){
		if (!initialisation){
			return true;
		}
		if (this.getActionStack().size() == 0){
			CentralObservableUnit.initialisationFinished(engine.getID(), engine.getScenarioParameter().getID(), engine.getSimulationEnviroment().getClock().getCurrentTime());
			this.initialisation = false;
			return true;
		}
		return false;
	}
}
